diff options
Diffstat (limited to 'app/[lng]/evcp/(evcp)/evaluation/page.tsx')
| -rw-r--r-- | app/[lng]/evcp/(evcp)/evaluation/page.tsx | 119 |
1 files changed, 84 insertions, 35 deletions
diff --git a/app/[lng]/evcp/(evcp)/evaluation/page.tsx b/app/[lng]/evcp/(evcp)/evaluation/page.tsx index 4c498104..ae626e58 100644 --- a/app/[lng]/evcp/(evcp)/evaluation/page.tsx +++ b/app/[lng]/evcp/(evcp)/evaluation/page.tsx @@ -1,5 +1,5 @@ // ================================================================ -// 4. PERIODIC EVALUATIONS PAGE +// 4. PERIODIC EVALUATIONS PAGE - 집계 뷰 지원 (정리된 버전) // ================================================================ import * as React from "react" @@ -8,7 +8,7 @@ import { type SearchParams } from "@/types/table" import { getValidFilters } from "@/lib/data-table" import { Shell } from "@/components/shell" import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" -import { HelpCircle } from "lucide-react" +import { HelpCircle, BarChart3, List, Info } from "lucide-react" import { Popover, PopoverContent, @@ -16,10 +16,15 @@ import { } from "@/components/ui/popover" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" +import { Alert, AlertDescription } from "@/components/ui/alert" import { PeriodicEvaluationsTable } from "@/lib/evaluation/table/evaluation-table" -import { getPeriodicEvaluations } from "@/lib/evaluation/service" -import { searchParamsEvaluationsCache } from "@/lib/evaluation/validation" +import { getPeriodicEvaluationsWithAggregation } from "@/lib/evaluation/service" +import { + searchParamsEvaluationsCache, + type GetEvaluationsSchema +} from "@/lib/evaluation/validation" import { InformationButton } from "@/components/information/information-button" + export const metadata: Metadata = { title: "협력업체 정기평가", description: "협력업체 정기평가 진행 현황을 관리합니다.", @@ -29,7 +34,7 @@ interface PeriodicEvaluationsPageProps { searchParams: Promise<SearchParams> } -// 프로세스 안내 팝오버 컴포넌트 +// 프로세스 안내 팝오버 컴포넌트 - 집계 뷰 설명 포함 function ProcessGuidePopover() { return ( <Popover> @@ -46,6 +51,7 @@ function ProcessGuidePopover() { 확정된 평가 대상 업체들에 대한 정기평가 절차입니다. </p> </div> + <div className="space-y-3 text-sm"> <div className="flex gap-3"> <div className="flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600"> @@ -84,48 +90,68 @@ function ProcessGuidePopover() { </div> </div> </div> + + {/* 집계 뷰 설명 추가 */} + <div className="border-t pt-3 space-y-2"> + <h5 className="font-medium text-sm flex items-center gap-1"> + <Info className="h-3 w-3" /> + 보기 모드 + </h5> + <div className="space-y-2 text-xs"> + <div className="flex items-center gap-2"> + <List className="h-3 w-3 text-blue-600" /> + <span className="font-medium">상세 뷰:</span> + <span className="text-muted-foreground">모든 평가 기록을 개별적으로 표시</span> + </div> + <div className="flex items-center gap-2"> + <BarChart3 className="h-3 w-3 text-purple-600" /> + <span className="font-medium">집계 뷰:</span> + <span className="text-muted-foreground">동일 벤더의 여러 division 평가를 평균으로 통합</span> + </div> + </div> + </div> </div> </PopoverContent> </Popover> ) } -// TODO: 이 함수들은 실제 서비스 파일에서 구현해야 함 -function getDefaultEvaluationYear() { - return new Date().getFullYear() +// 집계 모드 안내 컴포넌트 +function AggregatedModeNotice({ isAggregated }: { isAggregated: boolean }) { + if (!isAggregated) return null; + + return ( + <Alert className="mb-4 border-purple-200 bg-purple-50"> + <BarChart3 className="h-4 w-4 text-purple-600" /> + <AlertDescription className="text-purple-800"> + 현재 <strong>집계 뷰</strong>로 표시되고 있습니다. + 동일 벤더의 여러 division 평가 결과가 평균으로 통합되어 표시됩니다. + </AlertDescription> + </Alert> + ); } - - export default async function PeriodicEvaluationsPage(props: PeriodicEvaluationsPageProps) { const searchParams = await props.searchParams + + // ✅ nuqs 기반 파라미터 파싱 const search = searchParamsEvaluationsCache.parse(searchParams) const validFilters = getValidFilters(search.filters || []) - // 기본 필터 처리 - let basicFilters = [] - if (search.basicFilters && search.basicFilters.length > 0) { - basicFilters = search.basicFilters - } - - // 모든 필터를 합쳐서 처리 - const allFilters = [...validFilters, ...basicFilters] - - // 조인 연산자 - const joinOperator = search.basicJoinOperator || search.joinOperator || 'and'; - // 현재 평가년도 - const currentEvaluationYear = search.evaluationYear || getDefaultEvaluationYear() + const currentEvaluationYear = search.evaluationYear - // Promise.all로 감싸서 전달 + // ✅ 집계 모드를 지원하는 서비스 함수 사용 const promises = Promise.all([ - getPeriodicEvaluations({ + getPeriodicEvaluationsWithAggregation({ ...search, - filters: allFilters, - joinOperator, + filters: validFilters, }) ]) + // ✅ 현재 모드 표시용 변수 + const currentMode = search.aggregated ? "집계" : "상세" + return ( <Shell className="gap-4"> {/* 헤더 */} @@ -137,27 +163,47 @@ export default async function PeriodicEvaluationsPage(props: PeriodicEvaluations 협력업체 정기평가 </h2> <InformationButton pagePath="evcp/evaluation" /> + {/* <ProcessGuidePopover /> */} + </div> + <div className="flex items-center gap-2"> + <Badge variant="outline" className="text-sm"> + {currentEvaluationYear}년도 + </Badge> + {/* ✅ 현재 보기 모드 표시 */} + <Badge + variant={search.aggregated ? "default" : "secondary"} + className={`text-xs ${search.aggregated ? 'bg-purple-600' : ''}`} + > + <div className="flex items-center gap-1"> + {search.aggregated ? ( + <BarChart3 className="h-3 w-3" /> + ) : ( + <List className="h-3 w-3" /> + )} + {currentMode} 뷰 + </div> + </Badge> </div> - <Badge variant="outline" className="text-sm"> - {currentEvaluationYear}년도 - </Badge> </div> </div> </div> + + {/* ✅ 집계 모드 안내 */} + <AggregatedModeNotice isAggregated={search.aggregated} /> {/* 메인 테이블 */} <React.Suspense - key={JSON.stringify(searchParams)} + key={JSON.stringify(searchParams)} // 집계 모드 변경 시에도 리렌더링 fallback={ <DataTableSkeleton - columnCount={15} + columnCount={search.aggregated ? 17 : 15} // 집계 모드에서 컬럼 추가 searchableColumnCount={2} filterableColumnCount={8} cellWidths={[ "3rem", // checkbox "5rem", // 평가년도 - "5rem", // 평가기간 - "4rem", // 구분 + "5rem", // 평가기간 or 평가수 (집계 모드) + "6rem", // 구분 (집계 모드에서 더 넓게) "8rem", // 벤더코드 "12rem", // 벤더명 "4rem", // 내외자 @@ -168,7 +214,8 @@ export default async function PeriodicEvaluationsPage(props: PeriodicEvaluations "4rem", // 총점 "4rem", // 등급 "5rem", // 진행상태 - "8rem" // actions + "8rem", // actions + ...(search.aggregated ? ["5rem", "5rem"] : []) // 집계 모드 추가 컬럼 ]} shrinkZero /> @@ -177,6 +224,8 @@ export default async function PeriodicEvaluationsPage(props: PeriodicEvaluations <PeriodicEvaluationsTable promises={promises} evaluationYear={currentEvaluationYear} + // ✅ 현재 뷰 모드를 테이블 컴포넌트에 전달 + initialViewMode={search.aggregated ? "aggregated" : "detailed"} /> </React.Suspense> </Shell> |
